import WhistleBridge from '..';
import { getFormattedRes } from '../utils';
import { WhistleBridgePlugin } from '../type';

type AnyFunc = (...args: any[]) => any;

export default class FalconBridgePlugin implements WhistleBridgePlugin {
  public name: string = 'falcon-bridge';
  public root: WhistleBridge;
  public hasInitd: boolean = false;
  public originBridgeKey: string = '__Falcon';
  public excludePropKey: string[] = [];
  public excludeHandlerName: string[] = [];
  public receiveName = 'falconCall';

  static instance: FalconBridgePlugin = null;

  private initFalcon() {
    const Falcon = {
      _callbackMap: {},
      _addCallback: (func: AnyFunc, name?: string) => {
        const id = (name || '') + '-' + Date.now() + Math.random();
        window.Falcon._callbackMap[id] = func;
        return id;
      },
      _callbackMapOn: {},
      _addCallbackOn: (func: AnyFunc, name?: string) => {
        const id = (name || '') + '-' + Date.now() + Math.random();
        window.Falcon._callbackMapOn[id] = func;
        return id;
      },
      _addEventCallback: (name: string, func: AnyFunc) => {
        let funcSet = window.Falcon._callbackMap[name];
        if (!funcSet) {
          funcSet = window.Falcon._callbackMap[name] = new Set();
          window.Falcon._callbackMap[name] = funcSet;
        }
        funcSet.add(func);
      },
      _removeEventCallback: (name: string, func?: AnyFunc) => {
        if (!func) {
          delete window.Falcon._callbackMap[name];
          return;
        }

        let funcSet = window.Falcon._callbackMap[name];
        if (funcSet) {
          funcSet.delete(func);
          if (funcSet.size === 0) {
            delete window.Falcon._callbackMap[name];
          }
        }
      },
      callback: (jsonString: string, callbackId: string) => {
        console.log(jsonString, callbackId);
        const func = window.Falcon._callbackMap[callbackId];
        if (func) {
          func(getFormattedRes(jsonString));
          delete window.Falcon._callbackMap[callbackId];
          return;
        }

        const funcOn = window.Falcon._callbackMapOn[callbackId];
        if (funcOn) {
          funcOn(getFormattedRes(jsonString));
        }
      },
      call: (funcName: string, jsonString: string) => {
        console.log('call', funcName, jsonString);

        let funcSet = window.Falcon._callbackMap[funcName];
        if (funcSet) {
          let res;
          funcSet.forEach((func: AnyFunc) => {
            res = func(getFormattedRes(jsonString));
          });
          return res;
        }
      },
      sendCustomEvent: (apiName: string, jsonString: string) => {
        let funcSet = window.Falcon._callbackMap[apiName];
        if (funcSet) {
          let res;
          funcSet.forEach((func: AnyFunc) => {
            res = func(getFormattedRes(jsonString));
          });
          return res;
        }
      },
    };

    const bridgeFunc = (actionName: string, jsonString: string = null) => {
      const originData = JSON.parse(jsonString);
      console.log(actionName, originData);

      if (actionName === 'invokeSync' && Array.isArray(originData)) {
        switch (originData[2]) {
          case 'canIUse':
            return JSON.stringify({ data: true });
          default:
            return JSON.stringify({ data: {}, errCode: 0 });
        }
      }

      return null;
    };

    Object.defineProperties(window, {
      _falcon: {
        value: true,
      },
      prompt: {
        value: bridgeFunc,
      },
      Falcon: {
        value: Falcon,
      },
      falconCallback: {
        value: Falcon.callback,
        writable: true,
      },
      falconSendCustomEvent: {
        value: Falcon.sendCustomEvent,
        writable: true,
      },
    });
  }

  public onInit(params: any) {
    if (this.hasInitd) {
      return;
    }

    FalconBridgePlugin.instance = this;
    this.hasInitd = true;
    this.root = params.root as WhistleBridge;
    this.initFalcon();
  }

  private functionCalled(name: string, args: any[], stack: string) {
    console.log(arguments);
  }
}
